﻿namespace MyTRCP.Common.MyProtocol
{
    public class MyProtocolPayload : BitWalkableObj
    {
        public Guid SessionId
        {
            get
            {
                return new Guid(SessionIdBytes);
            }
            set
            {
                SessionIdBytes = value.ToByteArray();
            }
        }
        public int NextDatagramId
        {
            get
            {
                if (DatagramId == int.MaxValue)
                {
                    return 0;
                }
                else
                {
                    return DatagramId + 1;
                }
            }
        }
        public byte[] SessionIdBytes { get; set; } = new byte[16];
        public int DatagramId { get; set; }
        public bool IsClientSideSent { get; set; }//b7
        public bool IsResponse { get; set; }//b6
        public bool IsEncrypted { get; set; }//b5
        public bool IsThisDatagramChangeId { get; set; }//b4
        public bool IsHistoryReplay { get; set; }//b5
        //public byte DataFlag { get; set; }
        public PayloadTypeEnum DataType { get; set; }//b2:0
        public ushort DataLen { get; set; }
        public byte DataCheckSum { get; set; }
        public byte HeadCheckSum { get; set; }
        public byte[] Data { get; set; } = [];
        public MyProtocolPayload() { }
        public MyProtocolPayload(Guid sessionId, int datagramId, bool isClientSideSent, bool isResponse, bool isEncrypted, bool isThisDatagramChangeId, bool isHistoryReply, PayloadTypeEnum dataType, byte[] data)
        {
            SessionId = sessionId;
            DatagramId = datagramId;
            IsClientSideSent = isClientSideSent;
            IsResponse = isResponse;
            IsEncrypted = isEncrypted;
            IsThisDatagramChangeId = isThisDatagramChangeId;
            IsHistoryReplay = isHistoryReply;
            DataType = dataType;
            Data = data;
            SetDataLenAndChecksum();
        }
        public MyProtocolPayload(byte[] data, int pos, int len) : base(data, pos, len) { }
        public void SetDataLenAndChecksum()
        {
            DataLen = (ushort)Data.Length;
            DataCheckSum = Tools.ComputeChecksum(Data, 0, Data.Length);
            byte[] head = GetHeadBytes();
            HeadCheckSum = Tools.ComputeChecksum(head, 0, head.Length);
        }
        public bool ValidCheck()
        {
            byte[] head = GetHeadBytes();
            return DataLen == Data.Length && DataCheckSum == Tools.ComputeChecksum(Data, 0, Data.Length) && HeadCheckSum == Tools.ComputeChecksum(head, 0, head.Length);
        }
        private byte[] GetHeadBytes()
        {
            BitWalker bw = new BitWalker();
            return bw
                 .WriteBytes(SessionIdBytes)
                 .WriteBits(DatagramId, 32)
                 .WriteBit(IsClientSideSent)
                 .WriteBit(IsResponse)
                 .WriteBit(IsEncrypted)
                 .WriteBit(IsThisDatagramChangeId)
                 .WriteBit(IsHistoryReplay)
                 .WriteBits((byte)DataType, 3)
                 .WriteBits(DataLen, 16)
                 .WriteBits(DataCheckSum, 8)
                 .ToBytes();
        }
        public override BitWalker ReadFromBitWalker(BitWalker bw)
        {
            SessionIdBytes = bw.ReadBytes(16);
            DatagramId = (int)bw.ReadBits(32);
            IsClientSideSent = bw.ReadBit();
            IsResponse = bw.ReadBit();
            IsEncrypted = bw.ReadBit();
            IsThisDatagramChangeId = bw.ReadBit();
            IsHistoryReplay = bw.ReadBit();
            DataType = (PayloadTypeEnum)bw.ReadBits(3);
            DataLen = (ushort)bw.ReadBits(16);
            DataCheckSum = (byte)bw.ReadBits(8);
            HeadCheckSum = (byte)bw.ReadBits(8);
            Data = bw.ReadBytesToEnd();
            return bw;
        }

        public override BitWalker WriteToBitWalker(BitWalker bw)
        {
            return bw
                .WriteBytes(SessionIdBytes)
                .WriteBits(DatagramId, 32)
                .WriteBit(IsClientSideSent)
                .WriteBit(IsResponse)
                .WriteBit(IsEncrypted)
                .WriteBit(IsThisDatagramChangeId)
                .WriteBit(IsHistoryReplay)
                .WriteBits((byte)DataType, 3)
                .WriteBits(DataLen, 16)
                .WriteBits(DataCheckSum, 8)
                .WriteBits(HeadCheckSum, 8)
                .WriteBytes(Data);
        }
    }
}
